/*
 * Estrategia.java
 *
 * Created on 17 de mayo de 2008, 01:33 AM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package futbol.forrest.strategy;

import futbol.forrest.utils.Types.*;
import futbol.forrest.worldModel.WorldModel;
import futbol.tacticas.Comando;
import futbol.forrest.gemetry.VecPosition;
/**
 *
 * @author Pablo
 */
public class Strategy {
    
    private EvaluateAccion eval = new EvaluateAccion();
    //ver como resolvemos el tema del worldmodel, si va a ser creado aca o no. Lo que es claro es que la estrategia debe tener una 
    //referencia al modelo
    private WorldModel model = new WorldModel();
    
    /** Creates a new instance of Estrategia */
    public Strategy() {
    }
    
    Comando strategyWithBall(VecPosition posAgente, VecPosition posBall)
    {

            //SoccerCommand 	soc(CMD_ILLEGAL);
            VecPosition posGoal = new VecPosition(PITCH_LENGTH/2.0,(-1 + 2*(model.getCurrentCycle()%2)) * 0.4 * SS->getGoalWidth());
            double			maxEvalAccion, maxEvalDribble, maxEvalPassTo, maxEvalScore, maxEvalClearBall;
            DirectionT		dirDribble;
            ObjectT			agentePase;
            AngDeg			angScore;
            AccionT			mejorAccion;
            VecPosition		posAgentePase;	
            VecPosition		posGol;
            bool 			pelotaParada = false;		
            double 			distGoal = posAgente.getDistanceTo(WM->getPosOpponentGoal());

            if ( WM->isDeadBallUs() )
            {
                    // en caso de estar con la pelota en un tiro libre o pelota parada en gral. no vamos a
                    //retornar dribble, para esto se setea la variable pelotaParada
                    //por defecto aplico patear al arco..siempre y cuando no exista otra acci�n "mejor para ejecutar"
                    pelotaParada = true;
                    soc = kickTo(posGoal, SS->getBallSpeedMax()); 
            }	

            evaluacion = evaluacion2N;

    /*	
            if ( posAgente.getX() < -12.5 )
            {
                    evaluacion = evaluacion1N;
    //		Log.log(PNLog, "METODO EVAL: 1N - posX: %f", posAgente.getX());	   					
            }
            else
            {
                    evaluacion = evaluacion2N;
    //		Log.log(PNLog, "METODO EVAL: 2N - posX: %f", posAgente.getX());	   							
            }
    */	

            //Debo comensar a analizar las distintas acciones que se pueden ejecutar en lo inmediato (proximo ciclo)
            //Para cada tipo de accion, calculo cual es la mejor y despues comparo entre los distintos tipos.

            maxEvalAccion = -1;
            mejorAccion = ACCION_ILLEGAL;

            //Accion: Score
            maxEvalScore = evaluarScore ( posAgente, &angScore );		
            maxEvalAccion = maxEvalScore;

            if ( maxEvalAccion != -1 )
                    mejorAccion = ACCION_SCORE;


            //Accion: DRIBBLE
            if ( !pelotaParada )
            {
                    maxEvalDribble = evaluarDribble( posAgente, &dirDribble);

                    if ( maxEvalDribble > maxEvalAccion )
                    {
                            maxEvalAccion = maxEvalDribble;
                            mejorAccion = ACCION_DRIBBLE;
                    }
            }

            //Accion: PASSTO
            maxEvalPassTo = evaluarPassTo( posAgente, &agentePase );

            if ( maxEvalPassTo > maxEvalAccion && agentePase != OBJECT_ILLEGAL )
            {
                    maxEvalAccion = maxEvalPassTo;
                    mejorAccion = ACCION_PASSTO;
            }

            //Accion: CLEAR_BALL
            if ( !pelotaParada || mejorAccion == ACCION_ILLEGAL )
            {
                    maxEvalClearBall = evaluarClearBall( posAgente );
                    if ( maxEvalClearBall > maxEvalAccion )
                    {
                            maxEvalAccion = maxEvalClearBall;
                            mejorAccion = ACCION_CLEARBALL;
                    }
            }

    Log.log(PNLog, "");

            //eligo la mejor accion a ejecutar
            switch ( mejorAccion )
            {
                    case ACCION_SCORE:
                            Log.log(PNLog, "++MEJOR ACCION: SCORE - EVAL: %12.9f - angulo: %f", maxEvalAccion, angScore );	   			
                            posGol = Calculo::getPtoDePateo( posAgente, angScore );
                            soc = kickTo(posGol, SS->getBallSpeedMax()); 
                            break;

                    case ACCION_DRIBBLE:			
                            Log.log(PNLog, "++MEJOR ACCION: DRIBBLE - EVAL: %12.9f - angulo: %f", maxEvalAccion,  Calculo::directionToAngle( dirDribble ) );	   					
                            soc = dribble(Calculo::directionToAngle( dirDribble ), DRIBBLE_SLOW);
                            break;

                    case ACCION_PASSTO:						
                            Log.log(PNLog, "++MEJOR ACCION: PASSTO - EVAL: %12.9f - agente destino: %d", maxEvalAccion, agentePase );	   								
                            posAgentePase = WM->getGlobalPosition( agentePase );
                            soc = directPass( posAgentePase, PASS_NORMAL);
                            break;

                    case ACCION_CLEARBALL:
                            Log.log(PNLog, "++MEJOR ACCION: CLEARBALL - EVAL: %12.9f", maxEvalAccion);	   					

                            if ( distGoal < 25 )
                            {
                                    soc = clearBall( CLEAR_BALL_GOAL );
                                    Log.log(PNLog, "CLEARBALL GOAL");	   									
                            }
                            else if ( distGoal < 60 )
                            {
                                    soc = clearBall( CLEAR_BALL_OFFENSIVE );
                                    Log.log(PNLog, "CLEARBALL OFFENSIVE");	   													
                            }
                            else
                            {
                                    soc = clearBall( CLEAR_BALL_DEFENSIVE );										
                                    Log.log(PNLog, "CLEARBALL DEFENSIVE");	   																	
                            }

                            break;

                    default:
                            Log.log(PNLog, "++MEJOR ACCION: PATEO AL ARCO POR DEFECTO");
                            //este seria el caso que sea pelota parada y ninguna de las acciones alla macheado...
                            //entonces ejecuta el tiro al arco por defecto seteado anteriormente
                            break;
            }


            return soc;
    }

    double Forrest::evaluarScore( VecPosition posAgente, double *angScore )
    {
            VecPosition ptoNull;
            AngDeg ang;
            double eval;

            eval = -1;

            Log.log(PNLog, ".............ANALIZO SCORE.............");	   						
            if ( VariableEstado::esPosicionDeAtaque( posAgente ) )	
            {
                    eval = evaluacion->getEvaluacion(posAgente, ptoNull, ACCION_SCORE, &ang );
                    *angScore = ang;

                    Log.log(PNLog, "ACCION: SCORE - MEJOR EVAL: %12.9f", eval);	   					
                    Log.log(PNLog, " ");		
            }

            Log.log(PNLog, ".......................................");
            Log.log(PNLog, " ");		

            return eval;
    }

    double Forrest::evaluarDribble( VecPosition posAgente, DirectionT *dirDribbleP )
    {

            double 		evalMax = -1;
            double 		evalTemp;
            VecPosition	ptoFinal;
            DirectionT	dirDribbleMax = DIR_ILLEGAL;
            DirectionT	dirDribble[8];

            Log.log(PNLog, "...........ANALIZO DRIBBLES............");

            dirDribble[0]=DIR_NORTH; 			// Norte es la direccion del arco contrario
            dirDribble[1]=DIR_NORTHWEST; 					
            dirDribble[2]=DIR_NORTHEAST; 	

            //segun si se esta en posicion de ataque o no se consideran las direcciones Este y Oeste
            //el mexicano solo utiliza las direcciones 45, 0, -45.
            if ( VariableEstado::esPosicionDribbleEastWest( posAgente ) )
            {
                    dirDribble[3]=DIR_EAST; 					
                    dirDribble[4]=DIR_WEST; 						
                    dirDribble[5]=DIR_ILLEGAL; 					
            }
            else
            {

                    dirDribble[3] = DIR_ILLEGAL;
            }

            //para casa posible direccion, chequeo si hay espacio vacio y evaluo la pos final
            for ( int d = 0; dirDribble[d] != DIR_ILLEGAL; d++ )
            {
                    if ( VariableEstado::esEspacioVacio( posAgente, dirDribble[d] ) )
                    {	 		
                            Log.log(PNLog, "...........Direccion %d:", dirDribble[d]);		
                            ptoFinal = Calculo::calcularNuevoPto(posAgente, dirDribble[d], 5);				
                            evalTemp = evaluacion->getEvaluacion(posAgente, ptoFinal, ACCION_DRIBBLE );			
                            Log.log(PNLog, "ACCION: DRIBBLE - EVAL: %12.9f - DIR_DRIBBLE: %d", evalTemp, dirDribble[d]);	   			

                            if ( evalTemp > evalMax )
                            {	
                                    evalMax = evalTemp;
                                    dirDribbleMax = dirDribble[d];
                            }
                            Log.log(PNLog, "........................");							 															 					
                    }
                    else
                    {
                            Log.log(PNLog, "Direccion %d descartado por estar bloqueada", dirDribble[d]);						
                    }	 	
            }

            *dirDribbleP = dirDribbleMax;

            Log.log(PNLog, ".......................................");
            Log.log(PNLog, " ");		

            return evalMax;
    }

    private double evaluatePassTo(VecPosition posJugadorPasador, int nroJugadorMejorReceptor){
            ObjectT		mejorAgPase = OBJECT_ILLEGAL;
            VecPosition posGoal = WM->getPosOpponentGoal();
            VecPosition	posO;
            double		distAg, evalTemp, evalMax;
            int 		iIndex;

            evalMax = -1;
            Log.log(PNLog, ".............ANALIZO PASES.............");

            for( ObjectT o = WM->iterateObjectStart( iIndex, OBJECT_SET_TEAMMATES, -1.0 ); o != OBJECT_ILLEGAL; 
                     o = WM->iterateObjectNext ( iIndex, OBJECT_SET_TEAMMATES, -1.0 ) )    
            {

                    posO = WM->getGlobalPosition( o );
                    distAg = posO.getDistanceTo( posAgente );

                    if ( distAg > 1 && o != OBJECT_TEAMMATE_1 )
                    {
                            if ( VariableEstado::paseNoBloqueado( posAgente, posO, DIR_CENTER ) )
                            {
                                    Log.log(PNLog, "...........Jugador %d:", o);							 						
                                    evalTemp = evaluacion->getEvaluacion(posAgente, posO, ACCION_PASSTO);			
                                    Log.log(PNLog, "ACCION: PASSTO - EVAL: %12.9f - AGENTE_PASS: %d", evalTemp, o);	   					

                                    if ( evalTemp > evalMax )
                                    {	
                                            evalMax = evalTemp;
                                            mejorAgPase = o;
                                    }	  		
                                    Log.log(PNLog, "......................");							 														
                            }
                            else
                            {
                                    Log.log(PNLog, "Jugador %d descartado por estar bloqueado", o);						
                            }
                    }		
            }

            WM->iterateObjectDone( iIndex );

            Log.log(PNLog, ".......................................");
            Log.log(PNLog, " ");						

            *agentePase = mejorAgPase;

            return evalMax;
    }


    private double evaluateClearBall(VecPosition posAgente){
//        Log.log(PNLog, "...........ANALIZO CLEARBALL...........");	   							
        double eval = eval.getEvaluation(AccionT.ACCION_CLEARBALL, posAgente, new VecPosition());
//        Log.log(PNLog, "ACCION: CLEARBALL - EVAL: %12.9f", eval);	   		
//        Log.log(PNLog, ".......................................");	   							
        return eval;
    }

/*    
/******************************************/
/********** ESTRATEGIA SIN PELOTA *********/
/******************************************/

/*! Estrategia Sin Pelota de la defensa del equipo Forrest. */
SoccerCommand Forrest::estrategiaSinPelotaDefensa( bool pelotaNuestra )
{
 	SoccerCommand	soc(CMD_ILLEGAL);
	VecPosition		posAgente  = WM->getAgentGlobalPosition();
  	VecPosition		posPelota  = WM->getBallPos();
  	VecPosition		posArco  = WM->getPosOwnGoal();
 	ObjectT			yo = WM->getAgentObjectType();
 	ObjectT			ultimoDefensa, oponMarcar; 	
	double 			XultimoDefensa;  	
 	bool			voyPosEstrategica, seguiMarcando, pudeIr;
 	
 	if ( !pelotaNuestra )			//LA PELOTA LA TIENE UN CONTRARIO
 	{
		if ( distPelotaArco > 75.0 )
		{	
			/* La idea en esta situacion es:
			 * - si ya estaba marcando a alguien actualizo la marca
			 * - si no estoy en mi posicion estrategica me voy a ella 
			 * - miro para marcar a alguien de mi zona */
			
			//si ya estaba marcando a alguien..intento seguir marcandolo
			if ( m_objMarkOpp != OBJECT_ILLEGAL )
			{
				soc = seguirMarcando( obtTpoMarca( ), posArco, distMarca1, &seguiMarcando );
				if ( seguiMarcando )
				{
					//mientras este a una distancia de (distMarca1 + 1) del oponente a marcar lo sigo mirando, sino miro la pelota
					if ( (WM->getGlobalPosition(m_objMarkOpp)).getDistanceTo( posAgente ) > (distMarca1 + 1) )
						mirarPtoEstrategico( soc, m_objMarkOpp );
					else
						mirarPtoEstrategico( soc, OBJECT_BALL );
						
					return soc;
				}
			}
			
			//si no estoy en mi pos estrategica..voy a ella
			soc = irPosEstrategica( &voyPosEstrategica );
			if ( voyPosEstrategica )
			{
				mirarPtoEstrategico( soc, OBJECT_ILLEGAL );
				return soc;
			}
			
			//si tengo alguna marca para tomar..voy a marcar
			oponMarcar = obtOponMarca( posArco, distMarca1 + 1);  						
			if ( oponMarcar != OBJECT_ILLEGAL )
			{
				m_objMarkOpp = oponMarcar;
				ciclosConMarca = 0;				
				soc = mark( m_objMarkOpp , distMarca1, obtTpoMarca( ) );
				ACT->putCommandInQueue( soc );			
				mirarPtoEstrategico( soc, m_objMarkOpp );						
				return soc;
			}
			
			//ya estoy en mi pos estrategica y no tengo a nadie a quien marcar..
			//me quedo mirando estrategicamente
			soc = turnBodyToObject( OBJECT_BALL );
			ACT->putCommandInQueue( soc );				
			mirarPtoEstrategico( soc, OBJECT_ILLEGAL );						
			m_objMarkOpp = OBJECT_ILLEGAL;	 								 		
								
		}								
		else
		{
			/* La idea en esta situacion es:
			 * - si soy uno de los dos mas rapidos para ir a buscar la pelota...voy
			 * - si ya estaba marcando a alguien actualizo la marca
			 * - sino miro para marcar a alguien de mi zona
			 * - sino, me voy para mi posicion estrategica */
			
			//intento ir por la pelota..
			soc = voyPorLaPelota( &pudeIr );
			if ( pudeIr )
			{
				mirarPtoEstrategico( soc, OBJECT_BALL );
				return soc;
			}
			
			if ( WM->getPlayerNumber() != 3 ) 	
			{		
				//si ya estaba marcando a alguien..intento seguir marcandolo
				if ( m_objMarkOpp != OBJECT_ILLEGAL )
				{
					soc = seguirMarcando( obtTpoMarca( ), posArco, distMarca2, &seguiMarcando );
					if ( seguiMarcando )
					{
						//mientras este a una distancia de (distMarca2 + 1) del oponente a marcar lo sigo mirando, sino miro la pelota
						if ( (WM->getGlobalPosition(m_objMarkOpp)).getDistanceTo( posAgente ) > (distMarca2 + 1) )
							mirarPtoEstrategico( soc, m_objMarkOpp );
						else
							mirarPtoEstrategico( soc, OBJECT_BALL );
							
						return soc;
					}
				}
				
				//si tengo alguna marca para tomar..voy a marcar
				oponMarcar = obtOponMarca( posArco, distMarca2 + 1 );  						
				if ( oponMarcar != OBJECT_ILLEGAL )
				{
					m_objMarkOpp = oponMarcar;
					ciclosConMarca = 0;
					soc = mark( m_objMarkOpp , distMarca2, obtTpoMarca( ) );
					ACT->putCommandInQueue( soc );
					mirarPtoEstrategico( soc, m_objMarkOpp );						
					return soc;
				}
	
			}	
			
			//si no estoy en mi pos estrategica..voy a ella
			soc = irPosEstrategica( &voyPosEstrategica );
			if ( voyPosEstrategica )
			{
				mirarPtoEstrategico( soc, OBJECT_ILLEGAL );
				return soc;
			}
	
			//ya estoy en mi pos estrategica y no tengo a nadie a quien marcar..
			//me quedo mirando estrategicamente
			soc = turnBodyToObject( OBJECT_BALL );
			ACT->putCommandInQueue( soc );				
			mirarPtoEstrategico( soc, OBJECT_ILLEGAL );						
			m_objMarkOpp = OBJECT_ILLEGAL;	 								 		
	
		}
 	}
 	else			//LA PELOTA LA TIENE UN COMPA�ERO
 	{
		if ( distPelotaArco < 53.0 )
		{
			//Si soy el ultimo defensa, tengo que salir para no habilitar el offside
			ultimoDefensa = WM->obtUltimoDefensaNuestro ( &XultimoDefensa );
			if ( ultimoDefensa == yo && XultimoDefensa < posPelota.getX() )
			{
				//si no estoy en mi pos estrategica..voy a ella
				soc = irPosEstrategica( &voyPosEstrategica );
				if ( voyPosEstrategica )
				{
					mirarPtoEstrategico( soc, OBJECT_ILLEGAL );
					return soc;
				}			
			}
			
			//si ya estaba marcando a alguien..intento seguir marcandolo
			if ( m_objMarkOpp != OBJECT_ILLEGAL )
			{
				soc = seguirMarcando( obtTpoMarca(), posArco, distMarca1, &seguiMarcando );
				if ( seguiMarcando )
				{
					//mientras este a una distancia de (distMarca1 + 1) del oponente a marcar lo sigo mirando, sino miro la pelota
					if ( (WM->getGlobalPosition(m_objMarkOpp)).getDistanceTo( posAgente ) > (distMarca1 + 1) )
						mirarPtoEstrategico( soc, m_objMarkOpp );
					else
						mirarPtoEstrategico( soc, OBJECT_BALL );
						
					return soc;
				}
			}
			
			//si tengo alguna marca para tomar..voy a marcar
			oponMarcar = obtOponMarca( posArco, distMarca1 + 1);  						
			if ( oponMarcar != OBJECT_ILLEGAL )
			{
				m_objMarkOpp = oponMarcar;
				ciclosConMarca = 0;
				soc = mark( m_objMarkOpp , distMarca1, obtTpoMarca( ) );
				ACT->putCommandInQueue( soc );					
				mirarPtoEstrategico( soc, OBJECT_BALL );						
				return soc;
			}
					
			//ya estoy en mi pos estrategica y no tengo a nadie a quien marcar..
			//me quedo mirando estrategicamente
			soc = turnBodyToObject( OBJECT_BALL );
			ACT->putCommandInQueue( soc );				
			mirarPtoEstrategico( soc, OBJECT_ILLEGAL );						
			m_objMarkOpp = OBJECT_ILLEGAL;	 								 		
		    
		}
		else
		{
			//si ya estaba marcando a alguien..intento seguir marcandolo
			if ( m_objMarkOpp != OBJECT_ILLEGAL )
			{
				//me fijo si el oponente se encuentra dentro de la zona
				if ( zonaDeMarca.isInside( WM->getGlobalPosition(m_objMarkOpp) ) )
				{			
					soc = seguirMarcando( obtTpoMarca( ), posArco, distMarca1, &seguiMarcando );
					if ( seguiMarcando )
					{
						//mientras este a una distancia de (distMarca1 + 1) del oponente a marcar lo sigo mirando, sino miro la pelota
						if ( (WM->getGlobalPosition(m_objMarkOpp)).getDistanceTo( posAgente ) > (distMarca1 + 1) )
							mirarPtoEstrategico( soc, m_objMarkOpp );
						else
							mirarPtoEstrategico( soc, OBJECT_BALL );
							
						return soc;
					}
				}
				else
					m_objMarkOpp = OBJECT_ILLEGAL;				
						
			}
			
			//si no estoy en mi pos estrategica..voy a ella
			soc = irPosEstrategica( &voyPosEstrategica );
			if ( voyPosEstrategica )
			{
				mirarPtoEstrategico( soc, OBJECT_ILLEGAL );
				return soc;
			}
			
			//si tengo alguna marca para tomar..voy a marcar
			oponMarcar = obtOponMarca( posArco, distMarca1 + 1);  						
			if ( oponMarcar != OBJECT_ILLEGAL )
			{
				m_objMarkOpp = oponMarcar;
				ciclosConMarca = 0;
				soc = mark( m_objMarkOpp , distMarca1, obtTpoMarca( ) );
				ACT->putCommandInQueue( soc );		
				mirarPtoEstrategico( soc, m_objMarkOpp );						
				return soc;
			}
			
			//ya estoy en mi pos estrategica y no tengo a nadie a quien marcar..
			//me quedo mirando estrategicamente
			soc = turnBodyToObject( OBJECT_BALL );
			ACT->putCommandInQueue( soc );				
			mirarPtoEstrategico( soc, OBJECT_ILLEGAL );						
			m_objMarkOpp = OBJECT_ILLEGAL;	 								 		
		    
		} 		
 	}
 	
 	return soc;	
}
 
/*! Estrategia Sin Pelota del medio campo del equipo Forrest. */
SoccerCommand Forrest::estrategiaSinPelotaMedioCampo( bool pelotaNuestra )
{
 	SoccerCommand	soc(CMD_ILLEGAL);
	VecPosition		posAgente  = WM->getAgentGlobalPosition();
  	VecPosition		posPelota  = WM->getBallPos();
  	VecPosition		posArco  = WM->getPosOwnGoal();
 	bool			voyPosEstrategica, pudeIr;
 	
 	if ( !pelotaNuestra )			//LA PELOTA LA TIENE UN CONTRARIO
 	{
 	
		//intento ir por la pelota..
		soc = voyPorLaPelota( &pudeIr );
		if ( pudeIr )
		{
			mirarPtoEstrategico( soc, OBJECT_BALL );
			return soc;
		}
 	}
				
	//si no estoy en mi pos estrategica..voy a ella
	soc = irPosEstrategica( &voyPosEstrategica );
	if ( voyPosEstrategica )
	{
		mirarPtoEstrategico( soc, OBJECT_ILLEGAL );
		return soc;
	}
	
	//ya estoy en mi pos estrategica y no tengo a nadie a quien marcar..
	//me quedo mirando estrategicamente
	soc = turnBodyToObject( OBJECT_BALL );
	ACT->putCommandInQueue( soc );				
	mirarPtoEstrategico( soc, OBJECT_ILLEGAL );						
	m_objMarkOpp = OBJECT_ILLEGAL;	 								 		
      		 	
  	return soc;
  	
}
  
/*! Estrategia Sin Pelota de la defensa del equipo Forrest. */
SoccerCommand Forrest::estrategiaSinPelotaAtaque( bool pelotaNuestra )
{
  	//La idea es marcar por delante del defensa cuando la pelota la tiene el contrario
  	//y posicionarse estrategicamente cuando la tenemos nosotros
  	//Ademas, continuamente deben evaluar si es el mejor para ir en busca de la pelota
  	
 	SoccerCommand	soc(CMD_ILLEGAL);
	VecPosition		posAgente  = WM->getAgentGlobalPosition();
  	VecPosition		posPelota  = WM->getBallPos();
	VecPosition		posArcoOpon  = WM->getPosOpponentGoal();  	
 	ObjectT			oponMarcar;
 	bool			voyPosEstrategica, seguiMarcando, pudeIr;
 	

 	if ( !pelotaNuestra )			//LA PELOTA LA TIENE UN CONTRARIO
 	{ 	
 		//intento ir por la pelota...
		soc = voyPorLaPelota( &pudeIr );
		if ( pudeIr )
		{
			mirarPtoEstrategico( soc, OBJECT_BALL );
			return soc;
		}
 	 		
		//si ya estaba marcando a alguien..intento seguir marcandolo
		if ( m_objMarkOpp != OBJECT_ILLEGAL )
		{
			//lo sigo marcando si se encuentra dentro de la zona de marca..
			if ( zonaDeMarca.isInside( WM->getGlobalPosition(m_objMarkOpp) ) )
			{
				soc = seguirMarcando( obtTpoMarca( ), posAgente, distMarca3, &seguiMarcando );
				if ( seguiMarcando )
				{
					//mientras este a una distancia de (distMarca1 + 1) del oponente a marcar lo sigo mirando, sino miro la pelota
					if ( (WM->getGlobalPosition(m_objMarkOpp)).getDistanceTo( posAgente ) > (distMarca3 + 1) )
						mirarPtoEstrategico( soc, m_objMarkOpp );
					else
						mirarPtoEstrategico( soc, OBJECT_BALL );
						
					return soc;
				}
			}
			else
				m_objMarkOpp = OBJECT_ILLEGAL;
			
		}
		
		//si no estoy en mi pos estrategica..voy a ella
		soc = irPosEstrategica( &voyPosEstrategica );
		if ( voyPosEstrategica )
		{
			mirarPtoEstrategico( soc, OBJECT_ILLEGAL );
			return soc;
		}
		
 		 
 		//si la pelota esta dentro de la zona de marca....intento marcar a alguien
 		if ( zonaDeMarca.isInside( WM->getGlobalPosition(OBJECT_BALL) ) )
 		{
			//si tengo alguna marca para tomar..voy a marcar
			oponMarcar = obtOponMarca( posAgente, distMarca3 + 1);  						
			if ( oponMarcar != OBJECT_ILLEGAL )
			{
				m_objMarkOpp = oponMarcar;
				ciclosConMarca = 0;				
				soc = mark( m_objMarkOpp , distMarca3, obtTpoMarca( ) );
				ACT->putCommandInQueue( soc );			
				mirarPtoEstrategico( soc, m_objMarkOpp );						
				return soc;
			} 			 			
 		}
 		 				 		
		//ya estoy en mi pos estrategica y no tengo a nadie a quien marcar..
		//me quedo mirando estrategicamente
		soc = turnBodyToObject( OBJECT_BALL );
		ACT->putCommandInQueue( soc );				
		mirarPtoEstrategico( soc, OBJECT_ILLEGAL );						
		m_objMarkOpp = OBJECT_ILLEGAL;	 								 		
	    		
		return soc;								 		
 	}
 	else							//LA PELOTA LA TIENE NUESTRO EQUIPO
 	{
 		
 		//si no estoy en mi pos estrategica..voy a ella
		soc = irPosEstrategica( &voyPosEstrategica );
		if ( voyPosEstrategica )
		{
			mirarPtoEstrategico( soc, OBJECT_ILLEGAL );
			return soc;
		}
		
		//ya estoy en mi pos estrategica y no tengo a nadie a quien marcar..
		//me quedo mirando estrategicamente
		soc = turnBodyToObject( OBJECT_BALL );
		ACT->putCommandInQueue( soc );				
		mirarPtoEstrategico( soc, OBJECT_ILLEGAL );						
		m_objMarkOpp = OBJECT_ILLEGAL;	 								 		
				
		return soc;
 	}
} 
  
  
/******************************************/
/********** ESTRATEGIA DEL GOLERO *********/
/******************************************/

/*! Estrategia del golero*/
SoccerCommand Forrest::forrestGolero(  )
{
  int i;
  SoccerCommand soc;
  VecPosition   posAgent = WM->getAgentGlobalPosition();
  AngDeg        angBody  = WM->getAgentGlobalBodyAngle();

  // define the top and bottom position of a rectangle in which keeper moves
  static const VecPosition posLeftTop( -PITCH_LENGTH/2.0 +
               0.7*PENALTY_AREA_LENGTH, -PENALTY_AREA_WIDTH/4.0 );
  static const VecPosition posRightTop( -PITCH_LENGTH/2.0 +
               0.7*PENALTY_AREA_LENGTH, +PENALTY_AREA_WIDTH/4.0 );

  // define the borders of this rectangle using the two points.
  static Line  lineFront = Line::makeLineFromTwoPoints(posLeftTop,posRightTop);
  static Line  lineLeft  = Line::makeLineFromTwoPoints(
                         VecPosition( -50.0, posLeftTop.getY()), posLeftTop );
  static Line  lineRight = Line::makeLineFromTwoPoints(
                         VecPosition( -50.0, posRightTop.getY()),posRightTop );


  if( WM->isBeforeKickOff( ) )
  {
    if( formations->getFormation() != FT_INITIAL || // not in kickoff formation
        posAgent.getDistanceTo( WM->getStrategicPosition() ) > 2.0 )  
    {
      formations->setFormation( FT_INITIAL );       // go to kick_off formation
      ACT->putCommandInQueue( soc=teleportToPos(WM->getStrategicPosition()) );
    }
    else                                            // else turn to center
    {
      ACT->putCommandInQueue( soc = turnBodyToPoint( VecPosition( 0, 0 ), 0 ));
      ACT->putCommandInQueue( alignNeckWithBody( ) );
    }
    return soc;
  }

  if( WM->getConfidence( OBJECT_BALL ) < PS->getBallConfThr() )
  {                                                // confidence ball too  low
    ACT->putCommandInQueue( searchBall() );        // search ball
    ACT->putCommandInQueue( alignNeckWithBody( ) );
  }
  else if( WM->getPlayMode() == PM_PLAY_ON || WM->isFreeKickThem() ||
           WM->isCornerKickThem() )               
  {
    if( WM->isBallCatchable() )
    {
      ACT->putCommandInQueue( soc = catchBall() );
      ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
    }
     else if( WM->isBallKickable() )
    {
       soc = kickTo( VecPosition(0,posAgent.getY()*2.0), 2.0 );    
       ACT->putCommandInQueue( soc );
       ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
    }
    else if( WM->isInOwnPenaltyArea( getInterceptionPointBall( &i, true ) ) &&
             WM->getFastestInSetTo( OBJECT_SET_PLAYERS, OBJECT_BALL, &i ) == 
                                               WM->getAgentObjectType() )
    {
      ACT->putCommandInQueue( soc = intercept( true ) );
      ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
    }
    else
    {
      // make line between own goal and the ball
      VecPosition posMyGoal = ( WM->getSide() == SIDE_LEFT )
             ? SoccerTypes::getGlobalPositionFlag(OBJECT_GOAL_L, SIDE_LEFT )
             : SoccerTypes::getGlobalPositionFlag(OBJECT_GOAL_R, SIDE_RIGHT);
      Line lineBall = Line::makeLineFromTwoPoints( WM->getBallPos(),posMyGoal);

      // determine where your front line intersects with the line from ball
      VecPosition posIntersect = lineFront.getIntersection( lineBall );

      // outside rectangle, use line at side to get intersection
      if (posIntersect.isRightOf( posRightTop ) )
        posIntersect = lineRight.getIntersection( lineBall );
      else if (posIntersect.isLeftOf( posLeftTop )  )
        posIntersect = lineLeft.getIntersection( lineBall );

      if( posIntersect.getX() < -49.0 )
        posIntersect.setX( -49.0 );
        
      // and move to this position
      if( posIntersect.getDistanceTo( WM->getAgentGlobalPosition() ) > 0.5 )
      {
        soc = moveToPos( posIntersect, PS->getPlayerWhenToTurnAngle() );
        ACT->putCommandInQueue( soc );
        ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
      }
      else
      {
        ACT->putCommandInQueue( soc = turnBodyToObject( OBJECT_BALL ) );
        ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
      }
    }
  }
  else if( WM->isFreeKickUs() == true || WM->isGoalKickUs() == true )
  {
    if( WM->isBallKickable() )
    {
      if( WM->getTimeSinceLastCatch() == 25 && WM->isFreeKickUs() )
      {
        // move to position with lesser opponents.
        if( WM->getNrInSetInCircle( OBJECT_SET_OPPONENTS, 
                                          Circle(posRightTop, 15.0 )) <
            WM->getNrInSetInCircle( OBJECT_SET_OPPONENTS, 
                                           Circle(posLeftTop,  15.0 )) )
          soc.makeCommand( CMD_MOVE,posRightTop.getX(),posRightTop.getY(),0.0);
        else
          soc.makeCommand( CMD_MOVE,posLeftTop.getX(), posLeftTop.getY(), 0.0);
        ACT->putCommandInQueue( soc );
      }
      else if( WM->getTimeSinceLastCatch() > 28 )
      {
        soc = kickTo( VecPosition(0,posAgent.getY()*2.0), 2.0 );    
        ACT->putCommandInQueue( soc );
      }
      else if( WM->getTimeSinceLastCatch() < 25 )
      {
        VecPosition posSide( 0.0, posAgent.getY() ); 
        if( fabs( (posSide - posAgent).getDirection() - angBody) > 10 )
        {
          soc = turnBodyToPoint( posSide );
          ACT->putCommandInQueue( soc );
        }
        ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
      }
    }
    else if( WM->isGoalKickUs()  )
    {
      ACT->putCommandInQueue( soc = intercept( true ) );
      ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
    }
    else
      ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
  }
  else
  {
     ACT->putCommandInQueue( soc = turnBodyToObject( OBJECT_BALL ) );
     ACT->putCommandInQueue( turnNeckToObject( OBJECT_BALL, soc ) );
  }
  return soc;	
}	

*/
}
